function getRE() {
  let re = /[a-z]/;
  re.foo = 'bar';
  return re
}

let reg1 = getRE()
let reg2 = getRE()
console.log(reg1 === reg2)  // false  firefox 3.6中返回了true


// 许多【标点符号】具有特殊含义：^$.*+?=!:|\/()[]{}
/** 将直接量字符单独放进方括号内就组成了【字符类】。一个字符类可以匹配它所包含的任意字符。
 *  因此，正则表达式/[abc]/就和字母“a”、“b”、“c”中的任意一个都匹配
 *  [...] 方括号内任意字符
 *  [^...] 不在方括号内的任意字符
 *  .除换行符和其他Unicode终止符之外的任意字符
 *  \w 大小写字母数字
 *  \W \w的取反
 *  \s 空白符
 *  \S 非空白符
 *  \d 数字
 *  \D 非数字
 */

// 正则表达式的【重复字符】语法
/**
 * {n, m}: 匹配前一项至少n次，但不能超过m次
 * {n, }: 匹配前一项n次或者更多次
 * {n}: 匹配前一项n次
 * ?：匹配前一项o次或者1次，也就是说前一项是可选的，等价于{o,1}
 * +：匹配前一项1次或多次，等价于{1,}
 * *：匹配前一项0次或多次，等价于{0,}
 */

// 使用正则表达式进行【非贪婪匹配】。只须在待匹配的字符后跟随一个问号即可
let a = 'aaaa'
console.log(a.match(/a+/g))  //  [ 'aaaa' ]
console.log(a.match(/a+?/g))  // 非贪婪匹配[ 'a', 'a', 'a', 'a' ]

let b = 'aaaab'
console.log(b.match(/a+b/g)) // [ 'aaaab' ]
// 期望它能匹配一个a和最后一个b。但实际上，这个模式却匹配了整个字符串,
// 这是因为正则表达式的模式匹配总是会寻找字符串中第一个可能匹配的位置。由于该匹配是从字符串的第一个字符开始的，因此在这里不考虑它的子串中更短的匹配
console.log(b.match(/a+?b/g))// [ 'aaaab' ]


// 【选择、分组和引用】
// 字符“|”用于分隔供选择的字符
console.log(/ab|cd|ef/.exec('abcdefg'))  // ab
// 如果左边的选择项匹配，就忽略右边的匹配项，即使它产生更好的匹配
console.log(/ab|abc|ef/.exec('abcdefg'))  // ab

// ()作用是: 1.把单独的项组合成子表达式，以便可以像处理一个独立的单元那样用“|”、“*”、“+”或者“?”等来对单元内的项进行处理
console.log(/java(script)?/.exec('javascript')) // javascript
console.log(/java(script)?/.exec('javascr')) // java
// ()作用是2.是在完整的模式中定义子模式


/** 【选择、分组和引用字符】
 *  | 选择，匹配的是该符号左边的子表达式或右边的子表达式
 *  (...) 将几个项组合为一个单元，这个单元可通过“*”、“+”、“?”和“|”,等符号加以修饰，而且可以记住和这个组合相匹配的字符串以供此后的引用使用
 *  (?:...) 只组合，把项组合到一个单元，但不记忆与该组相匹配的字符
 *  \n   和第n个分组第一次匹配的字符相匹配，组是圆括号中的子表达式（也有可能是嵌套的)，组索引是从左到右的左括号数，“(?:”形式的分组不编码
 * */

/** 正则表达式中的【锚字符】
 * ^ 匹配字符串的开头，在多行检索中，匹配一行的开头
 * $ 匹配字符串的结尾，在多行检索中，匹配一行的结尾
 * \b 匹配一个单词的边界，简言之，就是位于字符\w和\w之间的位置，或位于字符\w和字符串的开头或者结尾之间的位置（但需要注意，[\b]匹配的是退格符)
 * \B 匹配非单词边界的位置
 * (?=p)  零宽正向先行断言，要求接下来的字符都与p匹配，但不能包括匹配p的那些字符
 * (!=p) 零宽负向先行断言，要求接下来的字符不与p匹配
 */

/** 正则表达式【修饰符】
 * i 执行不区分大小写的匹配
 * g 执行一个全局匹配，简言之，即找到所有的匹配，而不是在找到第一个之后就停止
 * m 多行匹配模式，^匹配一行的开头和字符串的开头，$匹配行的结束和字符串的结束
 * */


// 一段引用文本起始于双引号，结束于双引号,中间的内容不能包含引号
let quote = /"([^"]*)"/
// 正则表达式中使用圆括号括起来的子表达式是带有从左到右的索引编号的，而且正则表达式会记忆与每个子表达式匹配的文本。
// 如果在替换字符串中出现了$加数字，那么replace（）将用与指定的子表达式相匹配的文本来替换
console.log('"123456"aaaaaaaa'.replace(quote, '<$1>')) // <123456>aaaaaaaa
